package com.aiyige.page.advertisement.service;

import android.app.Notification;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;

import com.aiyige.base.db.dao.AdFileDao;
import com.aiyige.base.db.dao.AdModelDao;
import com.aiyige.base.db.table.AdFile;
import com.aiyige.base.db.table.AdModel;
import com.aiyige.page.advertisement.util.AdUtil;
import com.aiyige.page.my.download.service.DownloadService;
import com.aiyige.page.my.download.util.DownloadUtil;
import com.j256.ormlite.stmt.UpdateBuilder;
import com.j256.ormlite.stmt.Where;
import com.liulishuo.filedownloader.BaseDownloadTask;
import com.liulishuo.filedownloader.FileDownloadLargeFileListener;
import com.liulishuo.filedownloader.FileDownloadListener;
import com.liulishuo.filedownloader.FileDownloader;
import com.vondear.rxtools.RxFileTool;

import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import timber.log.Timber;

public class DownloadAdService extends Service {
    ScanThread scanThread;
    Handler mainHandler = null;
    Notification downloadServiceNotification;
    public static final int DOWNLOAD_SERVICE_NOTIFICATION_ID = 11;
    FileDownloadListener fileDownloadListener;
    volatile boolean shouldSendDownloadUpdateBroadcast = false;
    volatile boolean shouldSendDownloadProgressStatusUpadteBroadcast = false;
    volatile int downloadingFileNum = 0;
    volatile boolean firstRun = true;
    public DownloadAdService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        downloadingFileNum = 0;
        mainHandler = new Handler(Looper.getMainLooper());
        AdUtil.createStage();
        FileDownloader.getImpl().bindService(new Runnable() {
            @Override
            public void run() {
                FileDownloader.getImpl().setMaxNetworkThreadCount(AdUtil.MAX_DOWNLOAD_THREAD);
            }
        });
        FileDownloader.setGlobalPost2UIInterval(300);
        fileDownloadListener = new FileDownloadLargeFileListener() {
            @Override
            protected void completed(BaseDownloadTask task) {
                Timber.e("completed:");
                try {
                    UpdateBuilder<AdFile, String> updateBuilder = AdFileDao.getDao().updateBuilder();
                    updateBuilder.updateColumnValue(AdFile.PROGRESS_STATUS, DownloadUtil.PROGRESS_STATUS_DOWNLOAD_FINISHED);
                    updateBuilder.updateColumnValue(AdFile.DOWNLOAD_TIMESTAMP, System.currentTimeMillis());
                    updateBuilder.updateColumnValue(AdFile.FILE_LOCAL_URL, task.getTargetFilePath());
                    updateBuilder.where().eq(AdFile.ID, task.getTag());
                    updateBuilder.update();
                    shouldSendDownloadUpdateBroadcast = true;
                    downloadingFileNum--;
                } catch (Exception e) {
                    Timber.e("completed:" + Log.getStackTraceString(e));
                }
            }

            @Override
            protected void error(BaseDownloadTask task, Throwable e) {
                Timber.e("error:");
                downloadingFileNum--;
            }

            @Override
            protected void warn(BaseDownloadTask task) {
                Timber.e("warn:");
            }

            @Override
            protected void pending(BaseDownloadTask task, long soFarBytes, long totalBytes) {
                Timber.e("pending:");
            }

            @Override
            protected void progress(BaseDownloadTask task, long soFarBytes, long totalBytes) {
                Timber.e("progress:" + (float) soFarBytes / totalBytes);
                try {
                    UpdateBuilder<AdFile, String> updateBuilder = AdFileDao.getDao().updateBuilder();
                    updateBuilder.updateColumnValue(AdFile.DOWNLOADED_SIZE, soFarBytes);
                    updateBuilder.updateColumnValue(AdFile.TOTAL_SIZE, totalBytes);
                    updateBuilder.updateColumnValue(AdFile.DOWNLOAD_TIMESTAMP, System.currentTimeMillis());
                    updateBuilder.where().eq(AdFile.ID, task.getTag());
                    updateBuilder.update();
                    shouldSendDownloadUpdateBroadcast = true;
                } catch (SQLException e) {
                    Timber.e("progress:" + Log.getStackTraceString(e));
                }
            }

            @Override
            protected void paused(BaseDownloadTask task, long soFarBytes, long totalBytes) {
                Timber.e("paused:");
                downloadingFileNum--;
            }
        };
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (firstRun) {
            firstRun = false;
            scanThread = new ScanThread();
            scanThread.start();
        }
        return START_STICKY;
    }


    public static void startService(Context context) {
        context.startService(new Intent(context, DownloadAdService.class));
    }

    public class ScanThread extends Thread {
        volatile boolean stopWork = false;
        Lock mutex = new ReentrantLock();
        Condition waitCondition = mutex.newCondition();


        public ScanThread() {
        }

        @Override
        public void run() {
            while (true) {
                mutex.lock();
                if (stopWork) {
                    mutex.unlock();
                    break;
                }
                handleBroadcast();
                handleDelete();
                handlePause();
                handleDownload();
                handleDownloadFinish();
                if (checkFinish()) {
                    stopSelf();
                }

                try {
                    waitCondition.await(AdUtil.SCAN_INTERVAL_MS, TimeUnit.MILLISECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mutex.unlock();
            }
        }

        public void handleBroadcast() {
            if (shouldSendDownloadUpdateBroadcast) {
                sendDownloadUpdateBroadcast();
                shouldSendDownloadUpdateBroadcast = false;
            }

            if (shouldSendDownloadProgressStatusUpadteBroadcast) {
                sendDownloadProgressStatusUpdateBroadcast();
                shouldSendDownloadProgressStatusUpadteBroadcast = false;
            }
        }


        public void sendDownloadUpdateBroadcast() {
//            mainHandler.post(new Runnable() {
//                @Override
//                public void run() {
//                    AdUtil.sendDownloadUpdateBroadcast();
//                }
//            });
        }

        public void sendDownloadProgressStatusUpdateBroadcast() {
//            mainHandler.post(new Runnable() {
//                @Override
//                public void run() {
//                    AdUtil.sendDownloadProgressStatusUpdateBroadcast();
//                }
//            });
        }

        public void handlePause() {
            try {
                List<AdFile> adFileList = AdFileDao.getDao().queryBuilder()
                        .where()
                        .eq(AdFile.CONTROL_OPTION, AdUtil.CONTROL_OPTION_PAUSE)
                        .and()
                        .eq(AdFile.PROGRESS_STATUS, AdUtil.PROGRESS_STATUS_DOWNLOADING)
                        .query();
                for (AdFile adFile : adFileList) {
                    FileDownloader.getImpl().pause(adFile.getDownloadId());
                    UpdateBuilder<AdFile, String> updateBuilder = AdFileDao.getDao().updateBuilder();
                    updateBuilder.updateColumnValue(AdFile.PROGRESS_STATUS, AdUtil.PROGRESS_STATUS_WAITING_DOWNLOAD);
                    updateBuilder.where().eq(AdFile.ID, adFile.getId());
                    updateBuilder.update();
                }
            } catch (Exception e) {

            }
        }


        public void handleDownload() {
            if (downloadingFileNum >= AdUtil.MAX_DOWNLOAD_THREAD) {
                return;
            }
            List<AdFile> adFileList = new LinkedList<>();
            try {
                Where<AdFile, String> where = AdFileDao.getDao().queryBuilder().where();
                where.and(
                        where.eq(AdFile.CONTROL_OPTION, AdUtil.CONTROL_OPTION_DOWNLOAD),
                        where.or(
                                where.eq(AdFile.PROGRESS_STATUS, AdUtil.PROGRESS_STATUS_WAITING_DOWNLOAD),
                                where.eq(AdFile.PROGRESS_STATUS, AdUtil.PROGRESS_STATUS_DOWNLOADING)
                        )
                );
                adFileList = where.query();
            } catch (Exception e) {

            }
            for (AdFile adFile : adFileList) {
                if ((System.currentTimeMillis() - adFile.getDownloadTimestamp()) > AdUtil.DOWNLOAD_IDLE_TIMEOUT_MS) {
                    retryDownloadAdFile(adFile);
                }
            }
        }

        public void handleDownloadFinish() {
            try {
                List<AdModel> adModelList = AdModelDao.getDao().queryBuilder()
                        .where()
                        .ne(AdModel.CONTROL_OPTION, AdUtil.CONTROL_OPTION_DELETE)
                        .and()
                        .ne(AdModel.PROGRESS_STATUS, AdUtil.PROGRESS_STATUS_DOWNLOAD_FAILED)
                        .and()
                        .ne(AdModel.PROGRESS_STATUS, AdUtil.PROGRESS_STATUS_DOWNLOAD_FINISHED)
                        .query();
                for (AdModel adModel : adModelList) {
                    List<AdFile> AdFileList = AdFileDao.getDao().queryBuilder()
                            .where()
                            .eq(AdFile.PARENT_ID, adModel.getId())
                            .and()
                            .ne(AdFile.CONTROL_OPTION, AdUtil.CONTROL_OPTION_DELETE)
                            .and()
                            .ne(AdFile.PROGRESS_STATUS, AdUtil.PROGRESS_STATUS_DOWNLOAD_FINISHED)
                            .query();
                    if (AdFileList.isEmpty()) {
                        UpdateBuilder<AdModel, String> updateBuilder = AdModelDao.getDao().updateBuilder();
                        updateBuilder.updateColumnValue(AdModel.PROGRESS_STATUS, AdUtil.PROGRESS_STATUS_DOWNLOAD_FINISHED);
                        updateBuilder.where().eq(AdModel.ID, adModel.getId());
                        updateBuilder.update();
                        shouldSendDownloadProgressStatusUpadteBroadcast = true;
                    }
                }
            } catch (Exception e) {

            }
        }


        public void handleDelete() {
            try {
                List<AdFile> adFileList = AdFileDao.getDao().queryForEq(AdFile.CONTROL_OPTION, AdUtil.CONTROL_OPTION_DELETE);
                for (AdFile adFile : adFileList) {
                    FileDownloader.getImpl().pause(adFile.getDownloadId());
                    try {
                        RxFileTool.deleteFile(adFile.getFileLocalUrl());
                    } catch (Exception e) {
                    }
                    AdFileDao.getDao().deleteById(adFile.getId());
                    shouldSendDownloadProgressStatusUpadteBroadcast = true;
                }
            } catch (SQLException e) {
                Timber.e("handleDelete:" + Log.getStackTraceString(e));
            }
            try {
                List<AdModel> adModelList = AdModelDao.getDao().queryForEq(AdModel.CONTROL_OPTION, AdUtil.CONTROL_OPTION_DELETE);
                for (AdModel adModel : adModelList) {
                    AdModelDao.getDao().deleteById(adModel.getId());
                    shouldSendDownloadProgressStatusUpadteBroadcast = true;
                }
            } catch (Exception e) {
                Timber.e("handleDelete:" + Log.getStackTraceString(e));
            }
        }

        public boolean checkFinish() {
            try {
                List<AdModel> adModelList = AdModelDao.getDao().queryBuilder()
                        .where()
                        .ne(AdModel.PROGRESS_STATUS, AdUtil.PROGRESS_STATUS_DOWNLOAD_FINISHED)
                        .and()
                        .ne(AdModel.PROGRESS_STATUS, AdUtil.PROGRESS_STATUS_DOWNLOAD_FAILED)
                        .query();
                if (!adModelList.isEmpty()) {
                    return false;
                }
            } catch (Exception e) {
                Timber.e("handleDelete:" + Log.getStackTraceString(e));
            }
            return true;
        }

        public void retryDownloadAdFile(AdFile adFile) {
            try {
                UpdateBuilder<AdFile, String> updateBuilder = AdFileDao.getDao().updateBuilder();
                updateBuilder.updateColumnValue(AdFile.DOWNLOAD_TIMESTAMP, System.currentTimeMillis());
                updateBuilder.updateColumnValue(AdFile.PROGRESS_STATUS, AdUtil.PROGRESS_STATUS_DOWNLOADING);
                updateBuilder.where().eq(AdFile.ID, adFile.getId());
                updateBuilder.update();
            } catch (SQLException e) {
                Timber.e("retryDownloadAdFile:" + Log.getStackTraceString(e));
                return;
            }
            int downloadId = FileDownloader.getImpl()
                    .create(adFile.getFileRemoteUrl())
                    .setPath(adFile.getFileLocalUrl(), false)
                    .setTag(adFile.getId())
                    .setListener(fileDownloadListener)
                    .start();
            try {
                UpdateBuilder<AdFile, String> updateBuilder = AdFileDao.getDao().updateBuilder();
                updateBuilder.updateColumnValue(AdFile.DOWNLOAD_ID, downloadId);
                updateBuilder.where().eq(AdFile.ID, adFile.getId());
                updateBuilder.update();
                downloadingFileNum++;
            } catch (SQLException e) {
                Timber.e("retryDownloadAdFile:" + Log.getStackTraceString(e));
                FileDownloader.getImpl().pause(downloadId);
                return;
            }
        }

        public void shutdown() {
            mutex.lock();
            stopWork = true;
            waitCondition.signalAll();
            mutex.unlock();
            try {
                join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onDestroy() {
        downloadingFileNum = 0;
        FileDownloader.getImpl().pauseAll();
        if (scanThread != null) {
            scanThread.shutdown();
        }
        super.onDestroy();
    }
}
